package com.three.domain.player;

import com.google.common.collect.Sets;
import com.three.api.event.PlayerInfoChangeEvent;
import com.three.base.AbstractEntity;
import com.three.config.HeadPortraitConfig;
import com.three.config.LocationSetConfig;
import com.three.constant.GameConstants;
import com.three.constant.LanguageId;
import com.three.event.EventBus;
import com.three.exception.GameException;
import com.three.repository.PlayerRepository;
import com.three.utils.SpringUtils;
import com.three.utils.StringUtils;
import com.three.utils.WordsFilterUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.*;
import java.util.Set;

/**
 * Created by wangziqing on 2017/5/17 0017.
 */
@Entity
@Table(name = "t_player")
public class PlayerPo extends AbstractEntity {

    private static final Logger LOGGER = LoggerFactory.getLogger(PlayerPo.class);

    @Id
    @GeneratedValue
    private long playerId;
    @Column(name = "nick_name", nullable = false)
    private String nickName;// 昵称
    @Column(name = "head")
    private String head;// 头像
    @Column(name = "level")
    private int level;// 等级
    @Column(name = "exp")
    private long exp;// 经验
    @Column(name = "province_id")
    private int provinceID;// 省份id
    @Column(name = "ctiy")
    private String city;// 城市
    @Column(name = "phone")
    private long phone;// 手机
    @Column(name = "gender")
    private byte gender;// 性别
    @Column(name = "gold")
    private long gold;// 金币
    @Column(name = "diamond")
    private long diamond;// 钻石

    /**
     * 创建新的玩家
     *
     * @param nickName 玩家昵称
     * @return
     */
    public static PlayerPo createPlayer(String nickName) {
        LocationSetConfig locationSetConfig = LocationSetConfig.getLocationSetConfig(LocationSetConfig.DEFAULT_PROVINCE_ID);
        HeadPortraitConfig headPortraitConfig = HeadPortraitConfig.getHeadPortraitConfig(HeadPortraitConfig.DEFAULT_HEAD_PROTRAIT_ID);
        PlayerPo player = new PlayerPo();
        player.nickName = nickName;
        player.head = headPortraitConfig.getIconName();
        player.gender = (byte) headPortraitConfig.getGender();
        player.provinceID = LocationSetConfig.DEFAULT_PROVINCE_ID;
        player.city = locationSetConfig.getDefaultCityName();
        player.level = 0;
        player.exp = 0;
        player.phone = 0;
        player.gold = 0;
        player.diamond = 0;
        return player;
    }

    /**
     * 减少角色属性
     *
     * @param attrType {@link PlayerAttrType} 角色属性
     * @param value    值
     * @return
     */
    public boolean subAttrValue(PlayerAttrType attrType, long value) {
        if (value <= 0) {
            if (value < 0) {
                LOGGER.error("player sub attr value error!player={}, attrType={}, value={}", this, attrType, value);
            }
            return value == 0;
        }
        long oldValue = attrType.getAttrValue(this);// 旧值
        long latestValue = oldValue - value;// 新值
        attrType.setAttrValue(this, latestValue);
        latestValue = attrType.getAttrValue(this);
        // 持久化
        SpringUtils.getBean(PlayerRepository.class).save(this);
        if (LOGGER.isDebugEnabled()) {
            LOGGER.info("player={}, sub type={}, value={}, success.", playerId, attrType, oldValue - latestValue);
        }
        // 通知客户端
        attrType.onChanged(this, oldValue, latestValue, true);
        return oldValue != latestValue;
    }

    /**
     * 增加角色属性
     *
     * @param attrType {@link PlayerAttrType} 角色属性
     * @param value    值
     * @return
     */
    public boolean addAttrValue(PlayerAttrType attrType, long value) {
        if (value <= 0) {
            if (value < 0) {
                LOGGER.error("player add attr value error!player={}, attrType={}, value={}", this, attrType, value);
            }
            return value == 0;
        }
        long oldValue = attrType.getAttrValue(this);// 旧值
        long latestValue = oldValue + value;// 新值
        attrType.setAttrValue(this, latestValue);
        latestValue = attrType.getAttrValue(this);
        // 持久化
        SpringUtils.getBean(PlayerRepository.class).save(this);
        if (LOGGER.isDebugEnabled()) {
            LOGGER.info("player={}, add type={}, value={}, success.", playerId, attrType, latestValue - oldValue);
        }
        // 通知客户端
        attrType.onChanged(this, oldValue, latestValue, true);
        return oldValue != latestValue;
    }

    /**
     * 获取玩家属性值
     *
     * @param attrType {@link PlayerAttrType} 角色属性
     * @return
     */
    public long getAttrValue(PlayerAttrType attrType) {
        return attrType.getAttrValue(this);
    }

    /**
     * 修改玩家信息
     *
     * @param nickName   昵称
     * @param head       头像
     * @param gender     性别
     * @param provinceID 省份id
     * @param city       城市
     * @param phone      手机号码
     * @throws GameException 修改失败时候抛出异常
     */
    public void changePlayerInfo(long playerId,String nickName, String head, int gender, int provinceID, String city, long phone) throws GameException {
        // 检查数据是否有错
        if (nickName != null && (nickName.trim().equals("") || WordsFilterUtils.hasBadWords(nickName))) {
            LOGGER.error("change player nickName error!nickName={}", nickName);
            throw new GameException(LanguageId.PARAM_VALUE_ERROR, nickName);
        }
        if (head != null && head.trim().equals("")) {
            LOGGER.error("change player head error!head={}", head);
            throw new GameException(LanguageId.PARAM_VALUE_ERROR, head);
        }
        if (gender != GameConstants.INVALID_VALUE && gender != HeadPortraitConfig.GenderType.MALE && gender != HeadPortraitConfig.GenderType.FEMALE) {
            LOGGER.error("change player gender error!gender={}", gender);
            throw new GameException(LanguageId.PARAM_VALUE_ERROR, Integer.toString(gender));
        }
        if (provinceID != GameConstants.INVALID_VALUE) {
            if (city == null || !LocationSetConfig.check(provinceID, city)) {
                LOGGER.error("change player city info error!provinceID={}, city={}", provinceID, city);
                throw new GameException(LanguageId.PARAM_VALUE_ERROR, city);
            }
        }
        if (phone != GameConstants.INVALID_VALUE && !StringUtils.checkMobileNumber(String.valueOf(phone))) {
            LOGGER.error("change player phone error!phone={}", phone);
            throw new GameException(LanguageId.PARAM_VALUE_ERROR, Long.toString(phone));
        }
        // 设置为最新值
        Set<PlayerInfoChangeEvent> events= Sets.newHashSet();
        if (nickName != null&&!this.nickName.equals(nickName)){
            events.add(new PlayerInfoChangeEvent(playerId,PlayerInfoChangeEvent.PlayerInfoType.NICKNAME,this.nickName,nickName));
            this.nickName=nickName;
        }
        if (head != null&&!this.head.equals(head)){
            events.add(new PlayerInfoChangeEvent(playerId, PlayerInfoChangeEvent.PlayerInfoType.HEAD,this.head,head));
            this.head=head;
        }
        if (gender != GameConstants.INVALID_VALUE&&this.gender!=(byte)gender){
            events.add(new PlayerInfoChangeEvent(playerId,PlayerInfoChangeEvent.PlayerInfoType.GENDER,this.gender,gender));
            this.gender=(byte)gender;
        }
        if (provinceID != GameConstants.INVALID_VALUE&&this.provinceID!=provinceID) {
            events.add(new PlayerInfoChangeEvent(playerId,PlayerInfoChangeEvent.PlayerInfoType.PROVINCEID,this.provinceID,provinceID));
            this.provinceID = provinceID;
        }
        if (!this.equals(city)) {
            events.add(new PlayerInfoChangeEvent(playerId,PlayerInfoChangeEvent.PlayerInfoType.CITY,this.city,city));
            this.city = city;
        }
        if (phone != GameConstants.INVALID_VALUE&&this.phone!=phone){
            events.add(new PlayerInfoChangeEvent(playerId,PlayerInfoChangeEvent.PlayerInfoType.PHONE,this.phone,phone));
            this.phone = phone;
        }
        // 持久化
        SpringUtils.getBean(PlayerRepository.class).save(this);
        //通知内部事件总线
        if(CollectionUtils.isNotEmpty(events)){
            events.stream().forEach(e-> EventBus.I.post(e));
        }
    }

    public int getProvinceID() {
        return provinceID;
    }

    public long getPlayerId() {
        return playerId;
    }

    public String getNickName() {
        return nickName;
    }

    public String getHead() {
        return head;
    }

    public int getLevel() {
        return level;
    }

    public long getExp() {
        return exp;
    }

    public String getCity() {
        return city;
    }

    public long getPhone() {
        return phone;
    }

    public byte getGender() {
        return gender;
    }

    public long getGold() {
        return gold;
    }

    public long getDiamond() {
        return diamond;
    }

    @Override
    public long getEntityId() {
        return playerId;
    }

    protected void setGold(long gold) {
        this.gold = gold;
    }

    protected void setDiamond(long diamond) {
        this.diamond = diamond;
    }

    @Override
    public String toString() {
        return "PlayerPo{" +
                "playerId=" + playerId +
                ", nickName='" + nickName + '\'' +
                ", head=" + head +
                ", level=" + level +
                ", exp=" + exp +
                ", provinceID=" + provinceID +
                ", city='" + city + '\'' +
                ", phone=" + phone +
                ", gender=" + gender +
                ", gold=" + gold +
                ", diamond=" + diamond +
                '}';
    }

}
